#include "stdafx.h"

#include "hwinstdctrls.h"
#include "hwinapplication.h"
#include "hwinenvironment.h"

namespace harlinn
{
    namespace windows
    {
        // --------------------------------------------------------------------
        // ImageList
        // --------------------------------------------------------------------
        HWIN_EXPORT ImageListHandle::ImageListHandle(HIMAGELIST theHandle, bool closeHandle)
            : Base(theHandle, closeHandle)
        {
        }

        HWIN_EXPORT HIMAGELIST ImageListHandle::CreateImageList(int elementWidth, int elementHeight,int count, int growBy,ImageListFlags theFlags,ImageListColor color)
        {
            int flagsValue = int(theFlags) | int(color);
            HIMAGELIST result = ImageList_Create(elementWidth,elementHeight,flagsValue,count,growBy);
            if(!result)
            {
                ThrowLastOSError();
            }
            return result;
        }

        HWIN_EXPORT ImageListHandle::ImageListHandle(int elementWidth, int elementHeight,int count, int growBy,ImageListFlags theFlags,ImageListColor color)
            : Base(CreateImageList(elementWidth, elementHeight,count, growBy,theFlags,color), true)
        {
        }
        HWIN_EXPORT ImageListHandle::~ImageListHandle( )
        {
            if(OwnsHandle())
            {
                ImageList_Destroy(GetHIMAGELIST());
            }
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const BitmapHandle& bitmap)
        {
            if(ImageList_Add(GetHIMAGELIST(),bitmap.GetHBITMAP(),nullptr) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const std::shared_ptr<BitmapHandle>& bitmap)
        {
            CheckPointerNotNull(bitmap);
            if(ImageList_Add(GetHIMAGELIST(),bitmap->GetHBITMAP(),nullptr) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const BitmapHandle& bitmap, const BitmapHandle& mask)
        {
            if(ImageList_Add(GetHIMAGELIST(),bitmap.GetHBITMAP(),mask.GetHBITMAP()) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const std::shared_ptr<BitmapHandle>& bitmap, const std::shared_ptr<BitmapHandle>& mask)
        {
            CheckPointerNotNull(bitmap);
            HBITMAP hMask = 0;
            if(mask)
            {
                hMask = mask->GetHBITMAP();
            }
            if(ImageList_Add(GetHIMAGELIST(),bitmap->GetHBITMAP(),hMask) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const BitmapHandle& bitmap, COLORREF maskColor)
        {
            if(ImageList_AddMasked(GetHIMAGELIST(),bitmap.GetHBITMAP(),maskColor) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Add(const std::shared_ptr<BitmapHandle>& bitmap, COLORREF maskColor)
        {
            CheckPointerNotNull(bitmap);
            if(ImageList_AddMasked(GetHIMAGELIST(),bitmap->GetHBITMAP(),maskColor) < 0)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT ImageListHandle& ImageListHandle::Move(int indexOfDestinationImage, int indexOfSourceImage)
        {
            if(indexOfDestinationImage != indexOfSourceImage)
            {
                if(ImageList_Copy(GetHIMAGELIST(),indexOfDestinationImage,GetHIMAGELIST(),indexOfSourceImage,ILCF_MOVE) == 0)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }
        HWIN_EXPORT ImageListHandle& ImageListHandle::Swap(int indexOfFirstImage, int indexOfSecondImage)
        {
            if(indexOfFirstImage != indexOfSecondImage)
            {
                if(ImageList_Copy(GetHIMAGELIST(),indexOfFirstImage,GetHIMAGELIST(),indexOfSecondImage,ILCF_SWAP) == 0)
                {
                    ThrowLastOSError();
                }
            }
            return *this;
        }

        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::Clone( )
        {
            HIMAGELIST hImageList = ImageList_Duplicate(GetHIMAGELIST());
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,true);
            return result;
        }

        HWIN_EXPORT const ImageListHandle& ImageListHandle::BeginDrag(int indexOfTrackImage,int dxHotspot,int dyHotspot) const
        {
            if(ImageList_BeginDrag(GetHIMAGELIST(),indexOfTrackImage,dxHotspot,dyHotspot) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT const ImageListHandle& ImageListHandle::BeginDrag(int indexOfTrackImage,const POINT& hotspot) const
        {
            if(ImageList_BeginDrag(GetHIMAGELIST(),indexOfTrackImage,hotspot.x,hotspot.y) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT void ImageListHandle::DragEnter(HWND hwndLock,int x,int y)
        {
            if(ImageList_DragEnter(hwndLock,x,y) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::DragEnter(std::shared_ptr<Control> theControl,int x,int y)
        {
            CheckPointerNotNull(theControl);
            if(ImageList_DragEnter(theControl->GetSafeHandle(),x,y) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::DragLeave(HWND hwndLock)
        {
            if(ImageList_DragLeave(hwndLock) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::DragLeave(std::shared_ptr<Control> theControl)
        {
            CheckPointerNotNull(theControl);
            if(ImageList_DragLeave(theControl->GetSafeHandle()) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::DragMove(int x,int y)
        {
            if(ImageList_DragMove(x,y) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::DragShowNolock(bool showImage)
        {
            if(ImageList_DragShowNolock(showImage) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::EndDrag(void)
        {
            ImageList_EndDrag();
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::GetDragImage(POINT *ppt,POINT *pptHotspot)
        {
            HIMAGELIST hImageList = ImageList_GetDragImage(ppt,pptHotspot);
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,false);
            return result;
        }

        HWIN_EXPORT const ImageListHandle& ImageListHandle::Draw(int indexOfImage, HDC hDC, int x, int y, ImageListDrawFlags flags) const
        {
            if(ImageList_Draw(GetHIMAGELIST(),indexOfImage, hDC, x, y, UINT(flags)) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT const ImageListHandle& ImageListHandle::Draw(int indexOfImage, HDC hDC, int x, int y, int dx, int dy, COLORREF background, COLORREF foreground, ImageListDrawFlags flags) const
        {
            if(ImageList_DrawEx(GetHIMAGELIST(),indexOfImage, hDC, x, y, dx, dy, background, foreground, UINT(flags)) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT void ImageListHandle::Draw(const IMAGELISTDRAWPARAMS* imagelistDrawOarams)
        {
            if(ImageList_DrawIndirect(const_cast<IMAGELISTDRAWPARAMS*>(imagelistDrawOarams)) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::Draw(const IMAGELISTDRAWPARAMS& imagelistDrawOarams)
        {
            if(ImageList_DrawIndirect(const_cast<IMAGELISTDRAWPARAMS*>(&imagelistDrawOarams)) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT COLORREF ImageListHandle::GetBkColor( ) const
        {
            auto result = ImageList_GetBkColor(GetHIMAGELIST());
            return result;
        }
        HWIN_EXPORT COLORREF ImageListHandle::BackgroundColor( ) const
        {
            auto result = ImageList_GetBkColor(GetHIMAGELIST());
            return result;
        }

        HWIN_EXPORT std::shared_ptr<IconHandle> ImageListHandle::GetIcon(int indexOfImage,ImageListDrawFlags flags) const
        {
            auto hIcon = ImageList_GetIcon(GetHIMAGELIST(),indexOfImage,UINT(flags));
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<IconHandle>(hIcon,true);
            return result;
        }

        HWIN_EXPORT std::shared_ptr<IconHandle> ImageListHandle::GetIcon(int indexOfImage) const
        {
            auto hIcon = ImageList_GetIcon(GetHIMAGELIST(),indexOfImage,0);
            if(!hIcon)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<IconHandle>(hIcon,true);
            return result;
        }

        HWIN_EXPORT void ImageListHandle::GetIconSize(int* x, int* y) const
        {
            if(ImageList_GetIconSize(GetHIMAGELIST(),x, y) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::GetIconSize(SIZE& size) const
        {
            if(ImageList_GetIconSize(GetHIMAGELIST(),(int*)&size.cx, (int*)&size.cy) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT SIZE ImageListHandle::GetIconSize() const
        {
            SIZE result = {0,};
            if(ImageList_GetIconSize(GetHIMAGELIST(),(int*)&result.cx, (int*)&result.cy) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT void ImageListHandle::GetImageSize(int* x, int* y) const
        {
            if(ImageList_GetIconSize(GetHIMAGELIST(),x, y) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT void ImageListHandle::GetImageSize(SIZE& size) const
        {
            if(ImageList_GetIconSize(GetHIMAGELIST(),(int*)&size.cx, (int*)&size.cy) == FALSE)
            {
                ThrowLastOSError();
            }
        }
        HWIN_EXPORT SIZE ImageListHandle::GetImageSize() const
        {
            SIZE result = {0,};
            if(ImageList_GetIconSize(GetHIMAGELIST(),(int*)&result.cx, (int*)&result.cy) == FALSE)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT int ImageListHandle::Count() const
        {
            auto result = ImageList_GetImageCount(GetHIMAGELIST());
            return result;
        }
            
        HWIN_EXPORT const ImageListHandle& ImageListHandle::GetImageInfo(int theImageIndex, IMAGEINFO* imageinfo) const
        {
            CheckPointerNotNull(imageinfo);
            if(ImageList_GetImageInfo(GetHIMAGELIST(),theImageIndex, imageinfo) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }

        HWIN_EXPORT const ImageListHandle& ImageListHandle::GetImageInfo(int theImageIndex, IMAGEINFO& imageinfo) const
        {
            if(ImageList_GetImageInfo(GetHIMAGELIST(),theImageIndex, &imageinfo) == FALSE)
            {
                ThrowLastOSError();
            }
            return *this;
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::Load(HINSTANCE hInstance, const wchar_t* name, int imageWidth, int growBy, COLORREF maskColor, ImageListLoadFlags flags)
        {
            HIMAGELIST hImageList = ImageList_LoadImageW(hInstance, name, imageWidth, growBy, maskColor, IMAGE_BITMAP,UINT(flags));
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,int(flags & ImageListLoadFlags::Shared) != 0?false:true);
            return result;
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::LoadFromFile(const wchar_t* name, int imageWidth, int growBy, COLORREF maskColor, ImageListLoadFlags flags)
        {
            flags |= ImageListLoadFlags::LoadFromFile;
            HIMAGELIST hImageList = ImageList_LoadImageW(nullptr, name, imageWidth, growBy, maskColor, IMAGE_BITMAP,UINT(flags));
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,int(flags & ImageListLoadFlags::Shared) != 0?false:true);
            return result;
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::LoadFromFile(const wchar_t* name, int imageWidth )
        {
            ImageListLoadFlags flags = ImageListLoadFlags::LoadFromFile;
            HIMAGELIST hImageList = ImageList_LoadImageW(nullptr, name, imageWidth, 1, CLR_DEFAULT, IMAGE_BITMAP,UINT(flags));
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,true);
            return result;
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::Merge(int i1,HIMAGELIST himl2,int i2,int dx,int dy) const
        {
            return Merge(GetHIMAGELIST(),i1,himl2,i2,dx,dy);
        }
        HWIN_EXPORT std::shared_ptr<ImageListHandle> ImageListHandle::Merge(HIMAGELIST himl1, int i1,HIMAGELIST himl2,int i2,int dx,int dy)
        {
            HIMAGELIST hImageList = ImageList_Merge(himl1, i1,himl2,i2,dx,dy);
            if(!hImageList)
            {
                ThrowLastOSError();
            }
            auto result = std::make_shared<ImageListHandle>(hImageList,true);
            return result;
        }



        // --------------------------------------------------------------------
        // ButtonBase
        // --------------------------------------------------------------------
        class ButtonWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT ButtonWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT ButtonWindowClass::windowClassName = String(L"HarlinnWindowsButtonWindowClassName");

        typedef SuperClassMessageDispatcher<Button> ButtonMessageDispatcher;
        WNDPROC ButtonMessageDispatcher::ControlProcedure;

        HWIN_EXPORT ButtonWindowClass::ButtonWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            ButtonMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = ButtonMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT ButtonBase::ButtonBase( )
            : Base( ), 
              autoEllipsis(false)
              
        {
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> ButtonBase::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ButtonWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::button_class_name);
                auto newWindowClass = std::make_shared<ButtonWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD ButtonBase::GetStyle() const
        {
            auto result = Base::GetStyle();
            result |= WS_TABSTOP | WS_CHILD | WS_VISIBLE;
            return result;
        }

        HWIN_EXPORT bool ButtonBase::AutoEllipsis() const
        {
            return autoEllipsis;
        }
        HWIN_EXPORT ButtonBase& ButtonBase::SetAutoEllipsis(bool theValue)
        {
            autoEllipsis = theValue;
            return *this;
        }



        HWIN_EXPORT void ButtonBase::DoOnSetEnabled(bool theValue)
        {
            Button_Enable(this->GetSafeHandle(),theValue);
        }

        HWIN_EXPORT ButtonBase& ButtonBase::Click()
        {
            if(IsValid())
            {
                SendMessage(BM_CLICK);
            }
            else
            {
                this->DoOnClick();
            }
            return *this;
        }

        HWIN_EXPORT const ButtonBase& ButtonBase::GetTextMargin(RECT& margin) const
        {
            Button_GetTextMargin(GetSafeHandle(),&margin);
            return *this;
        }

        HWIN_EXPORT RECT ButtonBase::GetTextMargin( ) const
        {
            RECT margin = {0,};
            Button_GetTextMargin(GetSafeHandle(),&margin);
            return margin;
        }


        HWIN_EXPORT ButtonBase& ButtonBase::SetTextMargin(const RECT& margin)
        {
            Button_SetTextMargin(GetSafeHandle(),&margin);
            return *this;
        }

        HWIN_EXPORT const ButtonBase& ButtonBase::GetIdealSize(SIZE& preferredSize) const
        {
            Button_GetIdealSize(GetSafeHandle(),&preferredSize);
            return *this;
        }

        HWIN_EXPORT SIZE ButtonBase::GetIdealSize( ) const
        {
            SIZE result = {0,};
            Button_GetIdealSize(GetSafeHandle(),&result);
            return result;
        }


        HWIN_EXPORT void ButtonBase::DoOnClick()
        {
            OnClick(this);
        }

        HWIN_EXPORT void ButtonBase::DoOnCommand(Message& message)
        {
            WORD notificationCode = HIWORD(message.wParam);
            if((notificationCode == BN_CLICKED)&&(message.message == REFLECTED_WM_COMMAND))
            {
                this->DoOnClick();
            }
            Base::DoOnCommand(message);
        }

        // --------------------------------------------------------------------
        // PushButtonBase
        // --------------------------------------------------------------------
        HWIN_EXPORT PushButtonBase::PushButtonBase( )
            : isDefault(false)
        {
        }

        HWIN_EXPORT bool PushButtonBase::IsDefault() const
        {
            return isDefault;
        }
        HWIN_EXPORT PushButtonBase& PushButtonBase::SetDefault(bool theValue)
        {
            if(isDefault != theValue)
            {
                isDefault = theValue;
                if(IsValid())
                {
                    this->DoOnSetDefault(theValue);
                }
                this->DoOnDefaultChanged(theValue);
            }
            return *this;
        }

        HWIN_EXPORT void PushButtonBase::DoOnSetDefault(bool theValue)
        {
        }
        HWIN_EXPORT void PushButtonBase::DoOnDefaultChanged(bool theValue)
        {
            OnDefaultChanged(this,theValue);
        }



        // --------------------------------------------------------------------
        // Button
        // --------------------------------------------------------------------
        HWIN_EXPORT Button::Button( )
            : Base( )
        {
            
        }

        HWIN_EXPORT DWORD Button::GetStyle() const
        {
            DWORD result = Base::GetStyle();
            result |= BS_PUSHBUTTON | WS_TABSTOP;
            if(IsDefault())
            {
                result |= BS_DEFPUSHBUTTON;
            }
            else
            {
                result &= ~BS_DEFPUSHBUTTON;
            }

            return result;
        }

        HWIN_EXPORT void Button::DoOnSetDefault(bool theValue)
        {
            Base::DoOnSetDefault(theValue);
            if(IsValid())
            {
                DWORD style = Base::GetStyle();
                if(IsDefault())
                {
                    style |= BS_DEFPUSHBUTTON;
                }
                else
                {
                    style &= ~BS_DEFPUSHBUTTON;
                }
                Base::SetWindowStyle(style);
            }

        }


        // --------------------------------------------------------------------
        // DropDownButton
        // --------------------------------------------------------------------
        HWIN_EXPORT DropDownButton::DropDownButton( )
            : Base( )
        {
        }

        HWIN_EXPORT void DropDownButton::DoOnInitialize( )
        {
            popupMenu = std::make_shared<PopupMenu>( );
            popupMenu->Initialize(As<Component>());
        }


        HWIN_EXPORT DWORD DropDownButton::GetStyle() const
        {
            DWORD result = Base::GetStyle();
            
            if(IsDefault())
            {
                result |= BS_DEFSPLITBUTTON;
                result &= ~BS_SPLITBUTTON;
            }
            else
            {
                result &= ~BS_DEFSPLITBUTTON;
                result |= BS_SPLITBUTTON;
            }
            
            return result;
        }

        HWIN_EXPORT std::shared_ptr<PopupMenu> DropDownButton::Menu() const
        {
            return popupMenu;
        }

        HWIN_EXPORT void DropDownButton::DoOnSetDefault(bool theValue)
        {
            Base::DoOnSetDefault(theValue);
            if(IsValid())
            {
                DWORD style = Base::GetStyle();
                if(IsDefault())
                {
                    style |= BS_DEFPUSHBUTTON;
                    style &= ~BS_SPLITBUTTON;
                }
                else
                {
                    style &= ~BS_DEFPUSHBUTTON;
                    style |= BS_SPLITBUTTON;
                }
                Base::SetWindowStyle(style);
            }
        }

        HWIN_EXPORT void DropDownButton::DoOnNotify(Message& message)
        {
            Base::DoOnNotify(message);
            if(!message.handled)
            {
                if(message.message == REFLECTED_WM_NOTIFY)
                {
                    NMHDR* nmhdr = (NMHDR*)message.lParam;
                    if(nmhdr->code == BCN_DROPDOWN)
                    {
                        NMBCDROPDOWN* nmbcdropdown = (NMBCDROPDOWN*)message.lParam;
                        POINT pt;
                        pt.x = nmbcdropdown->rcButton.left;
                        pt.y = nmbcdropdown->rcButton.bottom;
                        ::ClientToScreen(nmbcdropdown->hdr.hwndFrom, &pt);

                        popupMenu->Show(As<Control>(),pt,nmbcdropdown->rcButton);
                        message.handled = true;
                        message.result = true;
                    }
                }
            }
        }


        // --------------------------------------------------------------------
        // CommandButton
        // --------------------------------------------------------------------
        HWIN_EXPORT CommandButton::CommandButton( )
            : Base( )
        {
            
        }

        HWIN_EXPORT DWORD CommandButton::GetStyle() const
        {
            DWORD result = Base::GetStyle();
            
            if(IsDefault())
            {
                result |= BS_DEFCOMMANDLINK;
                result &= ~BS_COMMANDLINK;
            }
            else
            {
                result &= ~BS_DEFCOMMANDLINK;
                result |= BS_COMMANDLINK;
            }

            return result;
        }

        HWIN_EXPORT void CommandButton::DoOnSetDefault(bool theValue)
        {
            Base::DoOnSetDefault(theValue);
            if(IsValid())
            {
                DWORD style = Base::GetStyle();
                if(IsDefault())
                {
                    style |= BS_DEFCOMMANDLINK;
                    style &= ~BS_COMMANDLINK;
                }
                else
                {
                    style &= ~BS_DEFCOMMANDLINK;
                    style |= BS_COMMANDLINK;
                }
                Base::SetWindowStyle(style);
            }
        }



        // --------------------------------------------------------------------
        // StateButton
        // --------------------------------------------------------------------
        HWIN_EXPORT StateButton::StateButton( )
            : Base( ), 
              checkState(CheckState::Unchecked),
              allowGrayed(false)
        {

        }

        HWIN_EXPORT void StateButton::DoOnHandleCreated( )
        {
            Base::DoOnHandleCreated( );
            int check = int(checkState);
            Button_SetCheck(GetSafeHandle(),check);
        }

        HWIN_EXPORT void StateButton::HandleMessage(Message& message)
        {
            Base::HandleMessage(message);
            if(!message.handled)
            {
                switch(message.message) 
                {
                case BM_SETCHECK:
                    {
                        harlinn::windows::CheckState theCheckState = harlinn::windows::CheckState(message.wParam);
                        if(checkState != theCheckState)
                        {
                            checkState = theCheckState;
                            this->DoOnCheckStateChanged(checkState);
                        }
                    }
                    break;
                }
            }
        }


        HWIN_EXPORT StateButton& StateButton::SetCheckState(harlinn::windows::CheckState theCheckState)
        {
            if(IsValid())
            {
                int check = int(theCheckState);
                Button_SetCheck(GetSafeHandle(),check);
            }
            else
            {
                if(checkState != theCheckState)
                {
                    checkState = theCheckState;
                    this->DoOnCheckStateChanged(checkState);
                }
            }
            return *this;
        }
        HWIN_EXPORT harlinn::windows::CheckState StateButton::CheckState() const
        {
            return checkState;
        }

        HWIN_EXPORT bool StateButton::AllowGrayed() const
        {
            return allowGrayed;
        }
        HWIN_EXPORT StateButton& StateButton::SetAllowGrayed(bool theValue)
        {
            if(allowGrayed != theValue)
            {
                allowGrayed = theValue;
            }
            return *this;
        }

        HWIN_EXPORT bool StateButton::Checked() const
        {
            return checkState == harlinn::windows::CheckState::Checked;
        }
        HWIN_EXPORT StateButton& StateButton::SetChecked(bool theValue)
        {
            SetCheckState(theValue?harlinn::windows::CheckState::Checked:harlinn::windows::CheckState::Unchecked);
            return *this;
        }

        HWIN_EXPORT StateButton& StateButton::Toggle()
        {
            if(checkState == CheckState::Unchecked)
            {
                SetCheckState(CheckState::Checked);
            }
            else if(checkState == CheckState::Checked)
            {
                if(allowGrayed)
                {
                    SetCheckState(CheckState::Indeterminate);
                }
                else
                {
                    SetCheckState(CheckState::Unchecked);;
                }
            }
            else
            {
                SetCheckState(CheckState::Unchecked);
            }
            return *this;
        }


        HWIN_EXPORT void StateButton::DoOnCheckStateChanged( harlinn::windows::CheckState theCheckState )
        {
            OnCheckStateChanged(this,theCheckState);
        }

        HWIN_EXPORT void StateButton::DoOnClick()
        {
            Toggle();
            Base::DoOnClick();
        }



        // --------------------------------------------------------------------
        // CheckBox
        // --------------------------------------------------------------------
        HWIN_EXPORT CheckBox::CheckBox( )
            : Base( )
        {
        }

        HWIN_EXPORT DWORD CheckBox::GetStyle() const
        {
            DWORD result = Base::GetStyle() | BS_CHECKBOX;
            return result;
        }

        // --------------------------------------------------------------------
        // RadioButton
        // --------------------------------------------------------------------
        HWIN_EXPORT RadioButton::RadioButton( )
            : Base( )
        {
            
        }


        HWIN_EXPORT DWORD RadioButton::GetStyle() const
        {
            DWORD result = Base::GetStyle() | BS_RADIOBUTTON;
            return result;
        }

        // --------------------------------------------------------------------
        // DateTimePicker
        // --------------------------------------------------------------------
        class DateTimePickerWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT DateTimePickerWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT DateTimePickerWindowClass::windowClassName = String(L"HarlinnWindowsDateTimePickerWindowClassName");

        typedef SuperClassMessageDispatcher<DateTimePicker> DateTimePickerMessageDispatcher;
        WNDPROC DateTimePickerMessageDispatcher::ControlProcedure;

        HWIN_EXPORT DateTimePickerWindowClass::DateTimePickerWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            DateTimePickerMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = DateTimePickerMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT DateTimePicker::DateTimePicker( )
            : Base( )
        {
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> DateTimePicker::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(DateTimePickerWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::datetimepick_class_name);
                auto newWindowClass = std::make_shared<DateTimePickerWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }


        HWIN_EXPORT DWORD DateTimePicker::GetStyle() const
        {
            return Base::GetStyle();
        }


        // --------------------------------------------------------------------
        // GroupBox
        // --------------------------------------------------------------------
        class GroupBoxWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT GroupBoxWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT GroupBoxWindowClass::windowClassName = String(L"HarlinnWindowsGroupBoxWindowClassName");

        typedef SuperClassMessageDispatcher<GroupBox> GroupBoxMessageDispatcher;
        WNDPROC GroupBoxMessageDispatcher::ControlProcedure;

        HWIN_EXPORT GroupBoxWindowClass::GroupBoxWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            GroupBoxMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = GroupBoxMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT GroupBox::GroupBox( )
            : Base( )
        {
            
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> GroupBox::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(GroupBoxWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::button_class_name);
                auto newWindowClass = std::make_shared<GroupBoxWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }


        HWIN_EXPORT DWORD GroupBox::GetStyle() const
        {
            return Base::GetStyle()| BS_GROUPBOX;
        }


        // --------------------------------------------------------------------
        // Label
        // --------------------------------------------------------------------
        class LabelWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT LabelWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT LabelWindowClass::windowClassName = String(L"HarlinnWindowsLabelWindowClassName");

        typedef SuperClassMessageDispatcher<Label> LabelMessageDispatcher;
        WNDPROC LabelMessageDispatcher::ControlProcedure;

        HWIN_EXPORT LabelWindowClass::LabelWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            LabelMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = LabelMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT Label::Label( )
            : Base( )
        {
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> Label::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(LabelWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::static_class_name);
                auto newWindowClass = std::make_shared<LabelWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD Label::GetStyle() const
        {
            return Base::GetStyle();
        }


        // --------------------------------------------------------------------
        // LinkLabel
        // --------------------------------------------------------------------
        class LinkLabelWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT LinkLabelWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT LinkLabelWindowClass::windowClassName = String(L"HarlinnWindowsLinkLabelWindowClassName");

        typedef SuperClassMessageDispatcher<LinkLabel> LinkLabelMessageDispatcher;
        WNDPROC LinkLabelMessageDispatcher::ControlProcedure;

        HWIN_EXPORT LinkLabelWindowClass::LinkLabelWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(*existingClass)
        {
            LinkLabelMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = LinkLabelMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT LinkLabel::LinkLabel( )
            : Base( )
        {
             
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> LinkLabel::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(LinkLabelWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::link_class_name);
                auto newWindowClass = std::make_shared<LinkLabelWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD LinkLabel::GetStyle() const
        {
            return Base::GetStyle();
        }


        HWIN_EXPORT void LinkLabel::DoOnClick(NMLINK* pNMLINK)
        {
            OnClick(this,pNMLINK);
        }

        HWIN_EXPORT void LinkLabel::DoOnNotify(Message& message)
        {
            Base::DoOnNotify(message);
            if(message.handled == false)
            {
                if((((LPNMHDR)message.lParam)->code == NM_CLICK)||(((LPNMHDR)message.lParam)->code == NM_RETURN))
                {
                    PNMLINK pNMLink = (PNMLINK)message.lParam;
                    this->DoOnClick(pNMLink);
                }
            }
        }



        // --------------------------------------------------------------------
        // ListControl
        // --------------------------------------------------------------------
        HWIN_EXPORT ListControl::ListControl( )
            : Base( )
        {
            
        }




        // --------------------------------------------------------------------
        // ComboBox
        // --------------------------------------------------------------------
        class ComboBoxWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT ComboBoxWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT ComboBoxWindowClass::windowClassName = String(L"HarlinnWindowsComboBoxWindowClassName");

        typedef SuperClassMessageDispatcher<ComboBox> ComboBoxMessageDispatcher;
        WNDPROC ComboBoxMessageDispatcher::ControlProcedure;

        HWIN_EXPORT ComboBoxWindowClass::ComboBoxWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            ComboBoxMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = ComboBoxMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT ComboBox::ComboBox( )
            : Base( )
        {

        }

        HWIN_EXPORT std::shared_ptr<WindowClass> ComboBox::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ComboBoxWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::combobox_class_name);
                auto newWindowClass = std::make_shared<ComboBoxWindowClass> (windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD ComboBox::GetStyle() const
        {
            return Base::GetStyle();
        }


        // --------------------------------------------------------------------
        // ListBox
        // --------------------------------------------------------------------
        class ListBoxWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT ListBoxWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT ListBoxWindowClass::windowClassName = String(L"HarlinnWindowsListBoxWindowClassName");

        typedef SuperClassMessageDispatcher<ListBox> ListBoxMessageDispatcher;
        WNDPROC ListBoxMessageDispatcher::ControlProcedure;

        HWIN_EXPORT ListBoxWindowClass::ListBoxWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            ListBoxMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = ListBoxMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT ListBox::ListBox( )
            : Base( )
        {

        }

        HWIN_EXPORT std::shared_ptr<WindowClass> ListBox::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ListBoxWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::listbox_class_name);
                auto newWindowClass = std::make_shared<ListBoxWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD ListBox::GetStyle() const
        {
            return Base::GetStyle();
        }

        // --------------------------------------------------------------------
        // CheckedListBox
        // --------------------------------------------------------------------
        HWIN_EXPORT CheckedListBox::CheckedListBox( )
            : Base( )
        {
        }


        HWIN_EXPORT DWORD CheckedListBox::GetStyle() const
        {
            return Base::GetStyle();
        }

        // --------------------------------------------------------------------
        // HeaderControlItem
        // --------------------------------------------------------------------
        HWIN_EXPORT HeaderControlItem::HeaderControlItem(HeaderControlItems* theHeaderControlItems)
            : Base(), 
              items(theHeaderControlItems),
              mask(HeaderControlItemMask::None),
              dimension(0),
              format(HeaderControlItemFormat::Default),
              imageIndex(I_IMAGENONE),
              order(-1),
              filterType(HeaderControlItemFilterType::None)
        {}


        HWIN_EXPORT HeaderControlItem::HeaderControlItem(HeaderControlItems* theHeaderControlItems, const String& theText)
        : Base(), 
              items(theHeaderControlItems),
              mask(HeaderControlItemMask::None),
              dimension(50),
              format(HeaderControlItemFormat::Default),
              imageIndex(I_IMAGENONE),
              order(-1),
              filterType(HeaderControlItemFilterType::None),
              text(theText)
        {}

        bool HeaderControlItem::IsHandleCreated() const
        {
            return items->headerControl->IsHandleCreated();
        }

        HWND HeaderControlItem::GetControlHandle() const
        {
            return items->headerControl->GetSafeHandle();
        }

        HeaderControl* HeaderControlItem::GetControl() const
        {
            return items->headerControl;
        }

        



        HWIN_EXPORT String HeaderControlItem::Text() const
        {
            return text;
        }
        HWIN_EXPORT HeaderControlItem& HeaderControlItem::SetText(const String& theText)
        {
            if(text != theText)
            {
                text = theText;
            }
            return *this;
        }


        
        HWIN_EXPORT HeaderControlItem& HeaderControlItem::Assign(const HDITEM& item)
        {
            if(item.mask & HDI_BITMAP)
            {
                if(item.hbm)
                {
                    bitmap = BitmapHandle::FromHandle(item.hbm,false);
                }
                else
                {
                    bitmap.reset();
                }
            }
            if(item.mask & HDI_FORMAT)
            {
                format = HeaderControlItemFormat(item.fmt);
            }
            if(item.mask & HDI_FILTER)
            {

            }
            if(item.mask & HDI_HEIGHT)
            {
                dimension = item.cxy;
            }
            if(item.mask & HDI_IMAGE)
            {
                imageIndex = item.iImage;
            }
            if(item.mask & HDI_LPARAM)
            {

            }
            if(item.mask & HDI_ORDER)
            {
                order = item.iOrder;    
            }

            if(item.mask & HDI_STATE)
            {
                if(item.state & HDIS_FOCUSED)
                {
                    auto index = IndexOf();
                    items->focusedIndex = index;
                }    
            }
            if(item.mask & HDI_TEXT)
            {
                String s(item.pszText,item.cchTextMax);
                if(text != s)
                {
                    text = s;
                }
            }
            
            
            return *this;
        }


        HWIN_EXPORT const HeaderControlItem& HeaderControlItem::AssignTo(HDITEM& item) const
        {
            if(bitmap)
            {
                item.hbm = bitmap->GetHBITMAP();
                item.mask |= HDI_BITMAP;
            }
            else
            {
                item.mask &= ~HDI_BITMAP;
            }
            item.mask |= HDI_FORMAT;
            item.fmt = int(format);
            if(items->headerControl->imageList)
            {
                item.iImage = imageIndex;
                item.mask |= HDI_IMAGE;
            }
            else
            {
                item.mask &= ~HDI_IMAGE;
            }
            if(dimension > 0)
            {
                item.mask |= HDI_HEIGHT;
                item.cxy = dimension;
            }
            else
            {
                item.mask &= ~HDI_HEIGHT;
            }
            if(order >= 0)
            {
                item.mask |= HDI_ORDER;
                item.iOrder = order;
            }
            else
            {
                item.mask &= ~HDI_ORDER;
            }
            if(text)
            {
                item.mask |= HDI_TEXT;
                item.pszText = (LPWSTR)text.c_str();
                item.cchTextMax = int(text.length());
            }
            else
            {
                item.mask &= ~HDI_TEXT;
            }
            return *this;
        }

        HWIN_EXPORT size_t HeaderControlItem::IndexOf() const
        {
            return items->IndexOf(this);
        }

        HWIN_EXPORT void HeaderControlItem::DoOnBeginDrag( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnBeginFilterEdit( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnBeginTrack( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnDividerDoubleClick( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnDropDown( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnEndDrag( NMHEADER* pNMHEADER )
        {
        }

        HWIN_EXPORT void HeaderControlItem::DoOnEndFilterEdit( NMHEADER* pNMHEADER )
        {
        }

        HWIN_EXPORT void HeaderControlItem::DoOnEndTrack( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnFilterButtonClicked( NMHDFILTERBTNCLICK* pNMHDFILTERBTNCLICK )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnFilterChange( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnGetDispInfo( NMHDDISPINFO* pNMHDDISPINFO)
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemChanged( NMHEADER* pNMHEADER)
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemChanging( NMHEADER* pNMHEADER)
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemClicked( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemDoubleClicked( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemKeyDown( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemStateIconClicked( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnItemOverflowButtonClicked( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnTrack( NMHEADER* pNMHEADER )
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnCustomDraw( NMCUSTOMDRAW* pNMCUSTOMDRAW) 
        {
        }
        HWIN_EXPORT void HeaderControlItem::DoOnRightClicked( const Point& mousePosition )
        {
        }


        HWIN_EXPORT void HeaderControlItem::InsertHDITEM()
        {
            if(IsHandleCreated())
            {
                HWND hWnd = GetControlHandle();
                int index = int(IndexOf());
                HDITEM hditem = {0,};
                this->AssignTo(hditem);
                if(Header_InsertItem(hWnd,index,&hditem) == -1)
                {
                    ThrowLastOSError();
                }
            }
        }
        HWIN_EXPORT void HeaderControlItem::UpdateHDITEM()
        {
            if(IsHandleCreated())
            {
                HWND hWnd = GetControlHandle();
                int index = int(IndexOf());
                HDITEM hditem = {0,};
                this->AssignTo(hditem);
                if(Header_SetItem(hWnd,index,&hditem) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
        }
        HWIN_EXPORT void HeaderControlItem::DeleteHDITEM()
        {
            auto index = IndexOf();
            items->RemoveAt(index);
        }

        // --------------------------------------------------------------------
        // HeaderControlItems
        // --------------------------------------------------------------------
        HWIN_EXPORT HeaderControlItems::HeaderControlItems(HeaderControl* theHeaderControl)
            : headerControl(theHeaderControl),focusedIndex(npos)
        {

        }

        void HeaderControlItems::DoOnHandleCreated( )
        {
            for(size_type i = 0; i < items.size(); i++)
            {
                auto& item = items.at(i);
                item->InsertHDITEM();
            }
        }


        HWIN_EXPORT HeaderControlItems::size_type HeaderControlItems::Count() const
        {
            return items.size();
        }

        HWIN_EXPORT HeaderControlItems::size_type HeaderControlItems::IndexOf(const HeaderControlItem* theItem) const
        {
            if(theItem)
            {
                for(size_type i = 0; i < items.size(); i++)
                {
                    auto item = items.at(i);
                    if(item)
                    {
                        if(item.get() == theItem)
                        {
                            return i;
                        }
                    }
                }
            }
            return npos;
        }

        HWIN_EXPORT HeaderControlItems::size_type HeaderControlItems::IndexOf(std::shared_ptr<const HeaderControlItem> theItem) const
        {
            if(theItem)
            {
                return IndexOf(theItem.get());
            }
            return npos;
        }

        HWIN_EXPORT std::shared_ptr<const HeaderControlItem> HeaderControlItems::FocusedItem() const
        {
            if(focusedIndex < items.size())
            {
                return items.at(focusedIndex);
            }
            return std::shared_ptr<const HeaderControlItem>();
        }

        HWIN_EXPORT std::shared_ptr<HeaderControlItem> HeaderControlItems::FocusedItem()
        {
            if(focusedIndex < items.size())
            {
                return items.at(focusedIndex);
            }
            return std::shared_ptr<HeaderControlItem>();
        }

        HWIN_EXPORT HeaderControlItems::size_type HeaderControlItems::FocusedIndex() const
        {
            return focusedIndex;
        }


        HWIN_EXPORT std::shared_ptr<const HeaderControlItem> HeaderControlItems::Add(const String& headerText)
        {
            auto result = make_object<HeaderControlItem>(this,headerText);
            items.push_back(result);
            result->InsertHDITEM();
            return result;
        }
        HWIN_EXPORT std::shared_ptr<const HeaderControlItem> HeaderControlItems::Add(const String& headerText, HorizontalAlignment alignment)
        {
            auto result = make_object<HeaderControlItem>(this,headerText);
            result->format |= HeaderControlItemFormat(int(alignment));
            items.push_back(result);
            result->InsertHDITEM();
            return result;
        }

        HWIN_EXPORT HeaderControlItems& HeaderControlItems::RemoveAt( size_type index )
        {
            if(index < items.size() )
            {
                items.erase(items.begin() + index);
                if(headerControl->IsHandleCreated())
                {
                    HWND hWnd = headerControl->GetSafeHandle();
                    if(Header_DeleteItem(hWnd,int(index)) == FALSE)
                    {
                        ThrowLastOSError();
                    }
                }
            }
            return *this;
        }
        


        // --------------------------------------------------------------------
        // HeaderControl
        // --------------------------------------------------------------------
        class HeaderControlWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT HeaderControlWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT HeaderControlWindowClass::windowClassName = String(L"HarlinnWindowsHeaderControlWindowClassName");

        typedef SuperClassMessageDispatcher<HeaderControl> HeaderControlMessageDispatcher;
        WNDPROC HeaderControlMessageDispatcher::ControlProcedure;

        HWIN_EXPORT HeaderControlWindowClass::HeaderControlWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            HeaderControlMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = HeaderControlMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }


        HWIN_EXPORT HeaderControl::HeaderControl( )
            : Base( ),
              items(new HeaderControlItems(this)),
              bitmapMargin(DefaultBitmapMargin())
        {
            
        }

        HWIN_EXPORT HeaderControl::~HeaderControl()
        {
            delete items;
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> HeaderControl::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(HeaderControlWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::header_class_name);
                auto newWindowClass = std::make_shared<HeaderControlWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD HeaderControl::GetStyle() const
        {
            return Base::GetStyle();
        }


        HWIN_EXPORT std::shared_ptr<ImageListHandle> HeaderControl::ImageList() const
        {
            return imageList;
        }

        HWIN_EXPORT HeaderControl& HeaderControl::SetImageList(const std::shared_ptr<ImageListHandle>& theImageList )
        {
            imageList = theImageList;
            if(IsHandleCreated())
            {
                if(imageList)
                {
                    Header_SetImageList(GetSafeHandle(),imageList->GetHIMAGELIST());
                }
                else
                {
                    Header_SetImageList(GetSafeHandle(),nullptr);
                }
            }
            return *this;
        }

        HWIN_EXPORT std::shared_ptr<ImageListHandle> HeaderControl::StateImageList() const
        {
            return stateImageList;
        }
        HWIN_EXPORT HeaderControl& HeaderControl::SetStateImageList(const std::shared_ptr<ImageListHandle>& theImageList )
        {
            stateImageList = theImageList;
            if(IsHandleCreated())
            {
                if(stateImageList)
                {
                    Header_SetStateImageList (GetSafeHandle(),stateImageList->GetHIMAGELIST());
                }
                else
                {
                    Header_SetStateImageList (GetSafeHandle(),nullptr);
                }
            }
            return *this;
        }


        

        HWIN_EXPORT Rectangle HeaderControl::GetItemRectangle(size_t theIndex) const
        {
            Rectangle result;
            if( SendMessage(HDM_GETITEMRECT,WPARAM(theIndex),LPARAM(&result)) == 0)
            {
                ThrowLastOSError();
            }
            return result;
        }
        HWIN_EXPORT Rectangle HeaderControl::GetItemRectangle(const HeaderControlItem* theItem) const
        {
            if(theItem == nullptr)
            {
                throw ArgumentNullException("theItem");
            }
            auto index = items->IndexOf(theItem);
            if(index == HeaderControlItems::npos)
            {
                throw ArgumentNullException("theItem is not an HeaderControlItem belonging to this HeaderControl");
            }
            return GetItemRectangle(index);
        }
        HWIN_EXPORT Rectangle HeaderControl::GetItemRectangle(std::shared_ptr<const HeaderControlItem> theItem) const
        {
            if(!theItem)
            {
                throw ArgumentNullException("theItem");
            }
            auto index = items->IndexOf(theItem);
            if(index == HeaderControlItems::npos)
            {
                throw ArgumentNullException("theItem is not an HeaderControlItem belonging to this HeaderControl");
            }
            return GetItemRectangle(index);
        }

        HWIN_EXPORT int HeaderControl::DefaultBitmapMargin()
        {
            return Environment::SystemMetrics::EdgeBorderWidth() * 3;
        }


        HWIN_EXPORT HeaderControl& HeaderControl::SetBitmapMargin(int theMargin)
        {
            bitmapMargin = theMargin;
            if(IsHandleCreated())
            {
                SendMessage(HDM_SETBITMAPMARGIN,theMargin);
            }
            return *this;
        }


        HWIN_EXPORT void HeaderControl::DoOnHandleCreated( )
        {
            items->DoOnHandleCreated();
        }
        HWIN_EXPORT void HeaderControl::DoOnWindowSubClassed( )
        {
        }

        HWIN_EXPORT void HeaderControl::DoOnBeginDrag( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnBeginDrag(pNMHEADER);
            OnBeginDrag(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnBeginFilterEdit( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnBeginFilterEdit(pNMHEADER);
            OnBeginFilterEdit(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnBeginTrack( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnBeginTrack(pNMHEADER);
            OnBeginTrack(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnDividerDoubleClick( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnDividerDoubleClick(pNMHEADER);
            OnDividerDoubleClick(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnDropDown( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnDropDown(pNMHEADER);
            OnDropDown(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnEndDrag( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnEndDrag(pNMHEADER);
            OnEndDrag(this,pNMHEADER,theItem);
        }

        HWIN_EXPORT void HeaderControl::DoOnEndFilterEdit( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnEndFilterEdit(pNMHEADER);
            OnEndFilterEdit(this,pNMHEADER,theItem);
        }

        HWIN_EXPORT void HeaderControl::DoOnEndTrack( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnEndTrack(pNMHEADER);
            OnEndTrack(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnFilterButtonClicked( NMHDFILTERBTNCLICK* pNMHDFILTERBTNCLICK, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnFilterButtonClicked(pNMHDFILTERBTNCLICK);
            OnFilterButtonClicked(this,pNMHDFILTERBTNCLICK,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnFilterChange( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnFilterChange(pNMHEADER);
            OnFilterChange(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnGetDispInfo( NMHDDISPINFO* pNMHDDISPINFO, const std::shared_ptr<HeaderControlItem>& theItem)
        {
            theItem->DoOnGetDispInfo(pNMHDDISPINFO);
            OnGetDispInfo(this,pNMHDDISPINFO,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemChanged( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem)
        {
            theItem->DoOnItemChanged(pNMHEADER);
            OnItemChanged(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemChanging( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem)
        {
            theItem->DoOnItemChanging(pNMHEADER);
            OnItemChanging(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemClicked( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnItemClicked(pNMHEADER);
            OnItemClicked(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemDoubleClicked( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnItemDoubleClicked(pNMHEADER);
            OnItemDoubleClicked(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemKeyDown( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnItemKeyDown(pNMHEADER);
            OnItemKeyDown(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemStateIconClicked( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnItemStateIconClicked(pNMHEADER);
            OnItemStateIconClicked(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnItemOverflowButtonClicked( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnItemOverflowButtonClicked(pNMHEADER);
            OnItemOverflowButtonClicked(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnTrack( NMHEADER* pNMHEADER, const std::shared_ptr<HeaderControlItem>& theItem )
        {
            theItem->DoOnTrack(pNMHEADER);
            OnTrack(this,pNMHEADER,theItem);
        }
        HWIN_EXPORT void HeaderControl::DoOnCustomDraw( NMCUSTOMDRAW* pNMCUSTOMDRAW) 
        {
            OnCustomDraw(this,pNMCUSTOMDRAW);
        }
        HWIN_EXPORT void HeaderControl::DoOnRightClicked( const Point& mousePosition )
        {
            OnRightClicked(this,mousePosition);
        }
        HWIN_EXPORT void HeaderControl::DoOnCaptureReleased( const Point& mousePosition )
        {
            OnCaptureReleased(this,mousePosition);
        }


        HWIN_EXPORT void HeaderControl::DoOnNotify(Message& message)
        {
            Base::DoOnNotify(message);
            if(message.handled == false)
            {
                NMHDR* pNMHDR = (NMHDR*) message.lParam;
                if(pNMHDR)
                {
                    switch(pNMHDR->code)
                    {
                    case HDN_BEGINDRAG:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnBeginDrag(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_BEGINFILTEREDIT:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnBeginFilterEdit(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_BEGINTRACK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnBeginTrack(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_DIVIDERDBLCLICK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnDividerDoubleClick(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_DROPDOWN:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnDropDown(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ENDDRAG:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnEndDrag(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ENDFILTEREDIT:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnEndFilterEdit(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ENDTRACK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnEndTrack(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_FILTERBTNCLICK:
                        {
                            NMHDFILTERBTNCLICK* pNMHDFILTERBTNCLICK = (NMHDFILTERBTNCLICK*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHDFILTERBTNCLICK->iItem);
                            this->DoOnFilterButtonClicked(pNMHDFILTERBTNCLICK,theItem);
                        }
                        break;
                    case HDN_FILTERCHANGE:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnFilterChange(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_GETDISPINFO:
                        {
                            NMHDDISPINFO* pNMHDDISPINFO = (NMHDDISPINFO*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHDDISPINFO->iItem);
                            this->DoOnGetDispInfo(pNMHDDISPINFO,theItem);
                        }
                        break;
                    case HDN_ITEMCHANGED:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemChanged(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ITEMCHANGING:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemChanging(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ITEMCLICK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemClicked(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ITEMDBLCLICK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemDoubleClicked(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ITEMKEYDOWN:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemKeyDown(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_ITEMSTATEICONCLICK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemStateIconClicked(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_OVERFLOWCLICK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnItemOverflowButtonClicked(pNMHEADER,theItem);
                        }
                        break;
                    case HDN_TRACK:
                        {
                            NMHEADER* pNMHEADER = (NMHEADER*)pNMHDR;
                            std::shared_ptr<HeaderControlItem>& theItem = items->items.at(pNMHEADER->iItem);
                            this->DoOnTrack(pNMHEADER,theItem);
                        }
                        break;
                    case NM_CUSTOMDRAW:
                        {
                            NMCUSTOMDRAW* pNMCUSTOMDRAW = (NMCUSTOMDRAW *)pNMHDR;
                            this->DoOnCustomDraw(pNMCUSTOMDRAW);
                        }
                        break;
                    case NM_RCLICK:
                        {
                            Point pt(message.pt);
                            this->DoOnRightClicked(pt);
                        }
                        break;
                    case NM_RELEASEDCAPTURE:
                        {
                            Point pt(message.pt);
                            this->DoOnCaptureReleased(pt);
                        }
                        break;
                    };
                }
            }
        }



        // --------------------------------------------------------------------
        // ListView
        // --------------------------------------------------------------------
        class ListViewWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT ListViewWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT ListViewWindowClass::windowClassName = String(L"HarlinnWindowsListViewWindowClassName");

        typedef SuperClassMessageDispatcher<ListView> ListViewMessageDispatcher;
        WNDPROC ListViewMessageDispatcher::ControlProcedure;

        HWIN_EXPORT ListViewWindowClass::ListViewWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            ListViewMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = ListViewMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT ListView::ListView( )
            : Base( )
        {
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> ListView::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ListViewWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::listview_class_name);
                auto newWindowClass = std::make_shared<ListViewWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD ListView::GetStyle() const
        {
            return Base::GetStyle();
        }


        // --------------------------------------------------------------------
        // MonthCalendar
        // --------------------------------------------------------------------
        class MonthCalendarWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT MonthCalendarWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT MonthCalendarWindowClass::windowClassName = String(L"HarlinnWindowsMonthCalendarWindowClassName");

        typedef SuperClassMessageDispatcher<MonthCalendar> MonthCalendarMessageDispatcher;
        WNDPROC MonthCalendarMessageDispatcher::ControlProcedure;

        HWIN_EXPORT MonthCalendarWindowClass::MonthCalendarWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(*existingClass)
        {
            MonthCalendarMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = MonthCalendarMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT MonthCalendar::MonthCalendar( )
            : Base( )
        {
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> MonthCalendar::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(MonthCalendarWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::monthcal_class_name);
                auto newWindowClass = std::make_shared<MonthCalendarWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD MonthCalendar::GetStyle() const
        {
            return Base::GetStyle();
        }



        // --------------------------------------------------------------------
        // TreeEditBase
        // --------------------------------------------------------------------
        HWIN_EXPORT TreeEditBase::TreeEditBase( )
            : Base( )
        {
            
        }


        // --------------------------------------------------------------------
        // EditBase
        // --------------------------------------------------------------------
        HWIN_EXPORT EditBase::EditBase(  )
            : Base( )
        {
            
        }



        // --------------------------------------------------------------------
        // TextEditBase
        // --------------------------------------------------------------------
        HWIN_EXPORT TextEditBase::TextEditBase(  )
            : Base( )
        {
        }

        // --------------------------------------------------------------------
        // TextEdit
        // --------------------------------------------------------------------
        class TextEditWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT TextEditWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT TextEditWindowClass::windowClassName = String(L"HarlinnWindowsTextEditWindowClassName");

        typedef SuperClassMessageDispatcher<TextEdit> TextEditMessageDispatcher;
        WNDPROC TextEditMessageDispatcher::ControlProcedure;

        HWIN_EXPORT TextEditWindowClass::TextEditWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            TextEditMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = TextEditMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT TextEdit::TextEdit( )
            : Base( )
        {

        }

        HWIN_EXPORT std::shared_ptr<WindowClass> TextEdit::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(TextEditWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::edit_class_name);
                auto newWindowClass = std::make_shared<TextEditWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD TextEdit::GetStyle() const
        {
            return Base::GetStyle();
        }


        HWIN_EXPORT bool TextEdit::CanUndo() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_CANUNDO));
            return messageResult != 0;

        }

        HWIN_EXPORT TextEdit& TextEdit::Undo()
        {
            SendMessage(EM_UNDO);
            return *this;
        }

        HWIN_EXPORT TextEdit& TextEdit::EmptyUndoBuffer()
        {
            SendMessage(EM_EMPTYUNDOBUFFER);
            return *this;
        }
        HWIN_EXPORT TextEdit& TextEdit::FmtLines(bool addSoftLinebreaks)
        {
            SendMessage(EM_FMTLINES,addSoftLinebreaks?TRUE:FALSE);
            return *this;
        }
        HWIN_EXPORT String TextEdit::CueBannerText( ) const
        {
            wchar_t buffer[1024] = {0,};
            if(SendMessage(EM_GETCUEBANNER,WPARAM(buffer),1024) != FALSE)
            {
                return String(buffer);
            }
            return String();
        }

        HWIN_EXPORT TextEdit& TextEdit::SetCueBannerText(const String& theText, bool displayWhileFocused  )
        {
            SetCueBannerText(theText.c_str(),displayWhileFocused);
            return *this;
        }
        HWIN_EXPORT TextEdit& TextEdit::SetCueBannerText(const wchar_t* theText, bool displayWhileFocused )
        {
            if(theText && theText[0])
            {
                SendMessage(EM_SETCUEBANNER,WPARAM(displayWhileFocused?TRUE:FALSE),LPARAM(theText));
            }
            else
            {
                SendMessage(EM_SETCUEBANNER,WPARAM(displayWhileFocused?TRUE:FALSE),LPARAM(L""));
            }
            return *this;
        }

        HWIN_EXPORT int TextEdit::GetFirstVisibleLine() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_GETFIRSTVISIBLELINE));
            return int(messageResult);
        }
        HWIN_EXPORT UINT TextEdit::TextLimit() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_GETLIMITTEXT));
            return UINT(messageResult);
        }
        HWIN_EXPORT TextEdit& TextEdit::SetTextLimit(UINT theValue)
        {
            SendMessage(UINT(EM_SETLIMITTEXT),theValue);
            return *this;
        }


        HWIN_EXPORT int TextEdit::LineIndex(int theIndex) const
        {
            LRESULT messageResult = SendMessage(UINT(EM_LINEINDEX),WPARAM(theIndex));
            return int (messageResult);
        }

        HWIN_EXPORT int TextEdit::LineLength(int theIndex) const
        {
            int lineIndex = LineIndex(theIndex);
            if(lineIndex >= 0)
            {
                LRESULT messageResult = SendMessage(UINT(EM_LINELENGTH),WPARAM(lineIndex));
                return int(messageResult);
            }
            return -1;
        }
        HWIN_EXPORT String TextEdit::Line(int theIndex) const
        {
            int lineLength = LineLength(theIndex);
            if(lineLength > 0 )
            {
                String result(nullptr,String::size_type(lineLength));
                *(WORD*)result.c_str() = WORD(lineLength);
                LRESULT messageResult = SendMessage(UINT(EM_GETLINE),WPARAM(theIndex),LPARAM(result.c_str()));
                result.Remove(messageResult);
                return result;
            }
            return String();
        }
        HWIN_EXPORT int TextEdit::LineCount() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_GETLINECOUNT));
            return int (messageResult);
        }
        HWIN_EXPORT bool TextEdit::IsModified() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_GETMODIFY));
            return messageResult != 0;
        }

        HWIN_EXPORT wchar_t TextEdit::PasswordChar() const
        {
            LRESULT messageResult = SendMessage(UINT(EM_GETPASSWORDCHAR));
            return wchar_t(messageResult);
        }
        HWIN_EXPORT TextEdit& TextEdit::SetPasswordChar(wchar_t theValue )
        {
            SendMessage(UINT(EM_SETPASSWORDCHAR),theValue);
            return *this;
        }

        HWIN_EXPORT Range TextEdit::Selection() const
        {
            DWORD start; 
            DWORD end;
            SendMessage(UINT(EM_GETSEL),WPARAM(&start),LPARAM(&end));
            return Range(start,end);
        }
        HWIN_EXPORT TextEdit& TextEdit::SetSelection(const Range& selectionRange )
        {
            SendMessage(UINT(EM_GETSEL),WPARAM(selectionRange.Start()),LPARAM(selectionRange.End()));
            return *this;
        }

        HWIN_EXPORT void TextEdit::DoOnSetEnabled(bool theValue)
        {
            Edit_Enable(this->GetSafeHandle(),theValue);
        }

        HWIN_EXPORT TextEdit& TextEdit::ReplaceSelection(const String& theText)
        {
            ReplaceSelection(theText.c_str());
            return *this;
        }
        HWIN_EXPORT TextEdit& TextEdit::ReplaceSelection(const wchar_t* theText)
        {
            if(theText && theText[0])
            {
                SendMessage(UINT(EM_REPLACESEL),FALSE,LPARAM(theText));
            }
            else
            {
                SendMessage(UINT(EM_REPLACESEL),FALSE,LPARAM(L""));
            }
            return *this;
        }
        HWIN_EXPORT TextEdit& TextEdit::Append(const String& theText)
        {
            Range currentSelection = Selection();
            int endOfText = TextLength();
            Range endSelection(endOfText,endOfText);
            SetSelection(endSelection);
            ReplaceSelection(theText);
            SetSelection(currentSelection);
            return *this;
        }


        HWIN_EXPORT TextEdit& TextEdit::Append(const wchar_t* theText)
        {
            if(theText && theText[0])
            {
                String s(theText);
                Append(s);
            }
            return *this;
        }



        // --------------------------------------------------------------------
        // MemoEdit
        // --------------------------------------------------------------------
        HWIN_EXPORT MemoEdit::MemoEdit( )
            : Base( )
        {
            
        }


        HWIN_EXPORT DWORD MemoEdit::GetStyle() const
        {
            return Base::GetStyle() | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL;
        }

        HWIN_EXPORT int MemoEdit::FirstVisibleLine() const
        {
            LRESULT messageResult = SendMessage(EM_GETFIRSTVISIBLELINE);
            return int(messageResult);
        }

        HWIN_EXPORT MemoEdit& MemoEdit::AppendLine(const String& theText)
        {
            auto length = theText.length();
            if(length)
            {
                String text(L"\r\n",2,theText.c_str(),length);
                Append(text);
            }
            return *this;
        }

        HWIN_EXPORT MemoEdit& MemoEdit::AppendLine(const wchar_t* theText)
        {
            if(theText && theText[0])
            {
                auto len = wcslen(theText);
                String s(L"\r\n",2,theText,len);
                Append(s);
            }
            return *this;
        }


        // --------------------------------------------------------------------
        // HotKey
        // --------------------------------------------------------------------
        class HotKeyWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT HotKeyWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT HotKeyWindowClass::windowClassName = String(L"HarlinnWindowsHotKeyWindowClassName");

        typedef SuperClassMessageDispatcher<HotKey> HotKeyMessageDispatcher;
        WNDPROC HotKeyMessageDispatcher::ControlProcedure;

        HWIN_EXPORT HotKeyWindowClass::HotKeyWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(existingClass)
        {
            HotKeyMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = HotKeyMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }


        HWIN_EXPORT HotKey::HotKey( )
            : Base()
        {}
        HWIN_EXPORT std::shared_ptr<WindowClass> HotKey::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(HotKeyWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::hotkey_class_name);
                auto newWindowClass = std::make_shared<HotKeyWindowClass>(windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }
        HWIN_EXPORT DWORD HotKey::GetStyle() const
        {
            DWORD result = Base::GetStyle();
            return result;
        }



        // --------------------------------------------------------------------
        // ScrollBar
        // --------------------------------------------------------------------
        class ScrollBarWindowClass : public WindowClass
        {
        public:
            typedef WindowClass Base;
            static String HWIN_EXPORT windowClassName;
            HWIN_EXPORT ScrollBarWindowClass(std::shared_ptr<WindowClass> existingClass);
        };

        String HWIN_EXPORT ScrollBarWindowClass::windowClassName = String(L"HarlinnWindowsScrollBarWindowClassName");

        typedef SuperClassMessageDispatcher<ScrollBar> ScrollBarMessageDispatcher;
        WNDPROC ScrollBarMessageDispatcher::ControlProcedure;

        HWIN_EXPORT ScrollBarWindowClass::ScrollBarWindowClass(std::shared_ptr<WindowClass> existingClass)
            : Base(*existingClass)
        {
            ScrollBarMessageDispatcher::ControlProcedure = existingClass->GetProcedure();
            SetName(windowClassName);
            WNDPROC procedure = ScrollBarMessageDispatcher::WndProc;
            SetProcedure(procedure);
        }

        HWIN_EXPORT ScrollBar::ScrollBar( )
            : Base( )
        {
            
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> ScrollBar::GetWindowClass() const
        {
            auto windowClass = Application::GetWindowClass(ScrollBarWindowClass::windowClassName);
            if(!windowClass)
            {
                auto windowsWindowClass = Application::GetWindowClass(WindowClass::scrollbar_class_name);
                auto newWindowClass = std::make_shared<ScrollBarWindowClass> (windowsWindowClass);
                newWindowClass->Register();
                return newWindowClass;
            }
            return windowClass;
        }

        HWIN_EXPORT DWORD ScrollBar::GetStyle() const
        {
            return Base::GetStyle();
        }


        // --------------------------------------------------------------------
        // HScrollBar
        // --------------------------------------------------------------------
        HWIN_EXPORT HScrollBar::HScrollBar( )
            : Base( )
        {

        }

        HWIN_EXPORT DWORD HScrollBar::GetStyle() const
        {
            return Base::GetStyle();
        }

        // --------------------------------------------------------------------
        // VScrollBar
        // --------------------------------------------------------------------
        HWIN_EXPORT VScrollBar::VScrollBar( )
            : Base( )
        {

        }

        HWIN_EXPORT DWORD VScrollBar::GetStyle() const
        {
            return Base::GetStyle();
        }

        // --------------------------------------------------------------------
        // Timer::TimerControl
        // --------------------------------------------------------------------
        UINT_PTR Timer::TimerControl::TimerID = 1;
        HWIN_EXPORT Timer::TimerControl::TimerControl(const std::shared_ptr<Timer> theTimer)
            : Base(),timer(theTimer),timerId(0)
        {
            SetVisible(false);
            SetEnabled(false);
            SetTabStop(false);
        }


        HWIN_EXPORT void Timer::TimerControl::HandleMessage(Message& message)
        {
            Base::HandleMessage(message);
            if(message.handled == false)
            {
                if((message.message == WM_TIMER) && (message.wParam == timerId))
                {
                    std::shared_ptr<Timer> t = timer.lock();
                    if(t)
                    {
                        t->DoOnTick();
                    }
                }
                else if(message.message == WM_CLOSE)
                {
                    StopTimer();
                }
            }
        }

        HWIN_EXPORT HWND Timer::TimerControl::CreateHandle( )
        {
            auto windowClass = this->GetWindowClass();
            HWND result = NULL;
            if(windowClass)
            {
                const String& className = windowClass->GetName();
                if(className.length())
                {
                    HWND hWndParent = HWND_MESSAGE;
                    result = ::CreateWindowExW(this->GetStyleEx(),
                        className.c_str(),
                        nullptr,this->GetStyle(),
                        0, 0, 0, 0, 
                        hWndParent,0,0,(LPVOID)this);
                    if(!result)
                    {
                        ThrowLastOSError();
                    }
                }
            }
            return result;
        }

        HWIN_EXPORT DWORD Timer::TimerControl::GetStyle() const
        {
            return Base::GetStyle();
        }

        HWIN_EXPORT void Timer::TimerControl::StopTimer()
        {
            if(IsHandleCreated())
            {
                if(KillTimer(GetSafeHandle(),timerId) == FALSE)
                {
                    ThrowLastOSError();
                }
            }
        }

        HWIN_EXPORT void Timer::TimerControl::StartTimer()
        {
            std::shared_ptr<Timer> t = timer.lock();
            if(t)
            {
                UINT period = UINT(t->interval.TotalMilliseconds());
                timerId = SetTimer(GetSafeHandle(),TimerID++,period,nullptr);
            }
        }



        HWIN_EXPORT void Timer::TimerControl::DoBeforeHandleDestroy( )
        {
            StopTimer();
            Base::DoBeforeHandleDestroy( );
            
        }


        // --------------------------------------------------------------------
        // Timer
        // --------------------------------------------------------------------
        HWIN_EXPORT Timer::Timer()
            : Base(),
              interval(TimeSpan::FromMilliseconds(100)),
              enabled(false)
        {}


        HWIN_EXPORT TimeSpan Timer::Interval() const
        {
            return interval;
        }
        HWIN_EXPORT Timer& Timer::SetInterval(TimeSpan& theInterval)
        {
            if(interval != theInterval)
            {
                interval = theInterval;
                if(timerControl)
                {
                    timerControl->StopTimer();
                    timerControl->StartTimer();
                }
            }
            return *this;
        }


        HWIN_EXPORT bool Timer::Enabled() const
        {
            return enabled;
        }
        HWIN_EXPORT Timer& Timer::SetEnabled(bool theValue)
        {
            if(enabled != theValue)
            {
                enabled = theValue;
                if(enabled)
                {
                    auto self = As<Timer>();
                    timerControl = std::make_shared<TimerControl>(self);
                    timerControl->StartTimer();
                }
                else if(timerControl)
                {
                    timerControl = std::shared_ptr<TimerControl>();
                }
            }
            return *this;
        }


        HWIN_EXPORT void Timer::DoOnTick()
        {
            OnTick(this);
        }



    }
}